package top.ochiamalu.aioj.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.reflect.TypeToken;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.socket.WebSocketSession;
import top.ochiamalu.aioj.common.ErrorCode;
import top.ochiamalu.aioj.constant.JudgeConstants;
import top.ochiamalu.aioj.constant.JudgeResultConstants;
import top.ochiamalu.aioj.domain.bo.ExecuteMessage;
import top.ochiamalu.aioj.domain.bo.JudgeComprehensiveBO;
import top.ochiamalu.aioj.domain.dto.judge.JudgeDTO;
import top.ochiamalu.aioj.domain.dto.judge.TestCodeDTO;
import top.ochiamalu.aioj.domain.entity.Answer;
import top.ochiamalu.aioj.domain.entity.ChoiceQuestion;
import top.ochiamalu.aioj.domain.entity.ComprehensiveQuestion;
import top.ochiamalu.aioj.domain.entity.FillBlanksQuestion;
import top.ochiamalu.aioj.domain.entity.JudgeCode;
import top.ochiamalu.aioj.domain.entity.JudgmentQuestion;
import top.ochiamalu.aioj.domain.entity.ProgrammingQuestion;
import top.ochiamalu.aioj.domain.entity.Question;
import top.ochiamalu.aioj.domain.entity.TestCase;
import top.ochiamalu.aioj.domain.entity.User;
import top.ochiamalu.aioj.domain.vo.judge.ExecuteCodeVO;
import top.ochiamalu.aioj.domain.vo.judge.SubmitHistoryVO;
import top.ochiamalu.aioj.domain.vo.judge.SubmitVO;
import top.ochiamalu.aioj.domain.vo.judge.TestCaseVO;
import top.ochiamalu.aioj.domain.vo.judge.TestCodeVO;
import top.ochiamalu.aioj.domain.vo.question.ChoiceOptionVO;
import top.ochiamalu.aioj.enums.QuestionTypeEnum;
import top.ochiamalu.aioj.exception.BusinessException;
import top.ochiamalu.aioj.factory.CodeExecutorFactory;
import top.ochiamalu.aioj.manager.JudgeManager;
import top.ochiamalu.aioj.mapper.JudgeMapper;
import top.ochiamalu.aioj.service.AnswerService;
import top.ochiamalu.aioj.service.ChoiceQuestionService;
import top.ochiamalu.aioj.service.ComprehensiveQuestionService;
import top.ochiamalu.aioj.service.FillBlanksQuestionService;
import top.ochiamalu.aioj.service.JudgeService;
import top.ochiamalu.aioj.service.JudgmentQuestionService;
import top.ochiamalu.aioj.service.ProgrammingQuestionService;
import top.ochiamalu.aioj.service.QuestionService;
import top.ochiamalu.aioj.service.TestCaseService;
import top.ochiamalu.aioj.service.UserService;
import top.ochiamalu.aioj.strategy.judge.CodeExecutor;
import top.ochiamalu.aioj.util.AIUtils;
import top.ochiamalu.aioj.util.model.AIResult;
import top.ochiamalu.aioj.websocket.JudgeHandler;

import javax.annotation.Resource;
import java.io.File;
import java.lang.reflect.Type;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 判题服务
 *
 * @author ochiamalu
 * @date 2025/01/20
 */
@Service
@Slf4j
public class JudgeServiceImpl extends ServiceImpl<JudgeMapper, JudgeCode>
        implements JudgeService {

    @Resource
    private QuestionService questionService;

    @Resource
    private TestCaseService testCaseService;

    @Resource
    private UserService userService;

    @Resource
    private AnswerService answerService;

    @Resource
    private ProgrammingQuestionService programmingQuestionService;

    @Resource
    private JudgeManager judgeManager;

    @Resource
    private CodeExecutorFactory codeExecutorFactory;

    @Resource
    private ChoiceQuestionService choiceQuestionService;

    @Resource
    private JudgmentQuestionService judgmentQuestionService;

    @Resource
    private FillBlanksQuestionService fillBlanksQuestionService;

    @Resource
    private ComprehensiveQuestionService comprehensiveQuestionService;

    private static final Gson GSON = new Gson();

    private static final Type STRING_LIST_TYPE = new TypeToken<List<String>>() {
    }.getType();

    /**
     * 判题
     *
     * @param judgeDTO     执行代码dto
     * @param submissionId 提交id
     */
    @Override
    public void judgeCode(JudgeDTO judgeDTO, String submissionId) {
        Answer answer = initializeAnswer(judgeDTO, submissionId);
        answer.setJudgeTime(new Date());

        // 获取题目信息
        String code = judgeDTO.getCode();
        if (StringUtils.isBlank(code)) {
            handleEmptyCode(answer, submissionId);
            return;
        }

        // 获取并验证测试用例
        List<TestCase> testCaseList = getTestCaseInfoList(judgeDTO.getQuestionId());
        LambdaQueryWrapper<Answer> queryWrapper = createSubmissionIdQueryWrapper(submissionId);

        if (!judgeManager.validateTestCases(testCaseList, answer, submissionId)) {
            answerService.update(answer, queryWrapper);
            return;
        }

        // 编译代码
        File userCodeFile = judgeManager.compileAndCheck(judgeDTO.getLanguage(), code, answer, submissionId);
        if (userCodeFile == null) {
            answerService.update(answer, queryWrapper);
            return;
        }

        try {
            // 运行代码
            List<ExecuteMessage> executeMessageList = judgeManager.executeCode(userCodeFile, testCaseList, judgeDTO.getLanguage());
            Map<Long, String> answerMap = testCaseList.stream()
                    .collect(Collectors.toMap(TestCase::getId, TestCase::getOutput));

            // 处理测试用例结果
            java.util.concurrent.atomic.AtomicInteger totalScore = new java.util.concurrent.atomic.AtomicInteger();
            List<TestCaseVO> testCaseVOList = handleTestCases(executeMessageList, answerMap, totalScore, submissionId, answer.getUserId());

            // 计算通过率
            long acceptedCount = testCaseVOList.stream()
                    .filter(testCase -> testCase.getStatus().equals(JudgeResultConstants.ACCEPTED))
                    .count();

            if (acceptedCount < testCaseList.size()) {
                answer.setStatus(JudgeResultConstants.PARTIAL_ACCEPTED);
            }
            if (acceptedCount == 0) {
                answer.setStatus(JudgeResultConstants.WRONG_ANSWER);
            }
            if (acceptedCount == testCaseList.size()) {
                answer.setStatus(JudgeResultConstants.ACCEPTED);
            }

            // 设置最终结果
            answer.setTime((int) getMaxTime(testCaseVOList));
            answer.setMemory((int) getMaxMemory(testCaseVOList));
            answer.setScore(totalScore.get());
        } finally {
            judgeManager.deleteCodeFile(userCodeFile, judgeDTO.getLanguage());
        }

        answerService.update(answer, queryWrapper);
    }

    /**
     * 得到判题结果
     *
     * @param submissionId 提交id
     * @return {@link ExecuteCodeVO }
     */
    @Override
    public ExecuteCodeVO getJudgeResult(String submissionId) {
        Answer answer = getAnswerBySubmissionId(submissionId);
        return buildExecuteCodeVO(answer, getUsername(submissionId));
    }

    /**
     * 获取提交信息
     *
     * @param judgeDTO     执行代码dto
     * @param submissionId 提交id
     * @return {@link SubmitVO }
     */
    @Override
    public SubmitVO getSubmitInfo(JudgeDTO judgeDTO, String submissionId) {
        long userId = StpUtil.getLoginIdAsLong();
        String username = userService.getById(userId).getUsername();
        Date submitTime = new Date();
        Question question = getQuestionById(judgeDTO.getQuestionId());
        judgeDTO.setQuestionType(question.getType());

        SubmitVO submitVO = new SubmitVO();
        submitVO.setSubmissionId(submissionId);
        submitVO.setQuestionName(question.getTitle());
        submitVO.setSubmitTime(submitTime);
        submitVO.setUsername(username);

        Answer answer = new Answer();
        answer.setQuestionId(judgeDTO.getQuestionId());
        answer.setSetId(judgeDTO.getSetId());
        answer.setSubmissionId(submissionId);
        answer.setSubmitTime(submitTime);

        if (question.getType().equals(QuestionTypeEnum.PROGRAMMING.getCode())) {
            submitVO.setCode(judgeDTO.getCode());
            submitVO.setCompiler(judgeManager.getCompilerName(judgeDTO.getLanguage()));
            answer.setLanguage(judgeDTO.getLanguage());
        }
        if (question.getType().equals(QuestionTypeEnum.MULTIPLE_CHOICE.getCode())) {
            List<Integer> multipleChoice = judgeDTO.getMultipleChoice();
            answer.setUserInput(GSON.toJson(multipleChoice));
        }
        if (question.getType().equals(QuestionTypeEnum.JUDGEMENT.getCode())) {
            answer.setUserInput(String.valueOf(judgeDTO.getJudgement()));
        }
        if (question.getType().equals(QuestionTypeEnum.FILL_BLANK.getCode())) {
            List<String> fillBlanks = judgeDTO.getFillBlanks();
            answer.setUserInput(GSON.toJson(fillBlanks));
        }
        if (question.getType().equals(QuestionTypeEnum.COMPREHENSIVE.getCode())) {
            String comprehensive = judgeDTO.getComprehensive();
            answer.setUserInput(comprehensive);
        }
        answerService.save(answer);

        return submitVO;
    }

    /**
     * 测试代码
     *
     * @param testCodeDTO 测试代码dto
     * @return {@link TestCodeVO }
     */
    @Override
    public TestCodeVO testCode(TestCodeDTO testCodeDTO) {
        TestCodeVO testCodeVO = new TestCodeVO();
        if (StringUtils.isBlank(testCodeDTO.getCode())) {
            testCodeVO.setResult("代码不能为空");
            return testCodeVO;
        }

        // 获取代码执行器
        CodeExecutor executor = codeExecutorFactory.getExecutor(testCodeDTO.getLanguage());

        // 编译代码
        File userCodeFile = executor.saveCodeToFile(testCodeDTO.getCode());

        ExecuteMessage compileMessage = executor.compileFile(userCodeFile);
        if (compileMessage.getExitValue() != 0) {
            executor.deleteFile(userCodeFile);
            String errorMessage = executor.handleErrorMessage(userCodeFile, compileMessage.getMessage());
            testCodeVO.setResult(errorMessage);
            return testCodeVO;
        }

        List<TestCase> testCaseList = new ArrayList<>();
        TestCase testCase = new TestCase();
        testCase.setInput(testCodeDTO.getTestCase());
        testCaseList.add(testCase);

        List<ExecuteMessage> executeMessageList = executor.runFile(userCodeFile, testCaseList);
        String message = executeMessageList.get(0).getMessage();
        testCodeVO.setResult(message);

        executor.deleteFile(userCodeFile);
        return testCodeVO;
    }

    /**
     * 得到最后判题结果
     *
     * @param questionId 题目ID
     * @return {@link ExecuteCodeVO }
     */
    @Override
    public ExecuteCodeVO getLastJudgeResult(Long questionId) {
        Long userId = getCurrentUserId();
        if (userId == null) {
            return null;
        }

        Answer answer = getLastAnswerByUserAndQuestion(userId, questionId);
        User user = userService.getById(userId);

        return buildExecuteCodeVO(answer, user.getUsername());
    }

    /**
     * 具有最后判题结果
     *
     * @param questionId 题目ID
     * @return boolean
     */
    @Override
    public boolean hasLastJudgeResult(Long questionId) {
        Long userId = getCurrentUserId();
        if (userId == null) {
            return false;
        }

        Long count = answerService.lambdaQuery()
                .eq(Answer::getUserId, userId)
                .eq(Answer::getQuestionId, questionId)
                .orderByDesc(Answer::getSubmitTime)
                .last("limit 1")
                .count();
        return count > 0;
    }

    /**
     * 获取提交历史记录
     *
     * @param account 账户
     * @return {@link SubmitHistoryVO }
     */
    @Override
    public SubmitHistoryVO getSubmitHistory(String account) {
        User user = userService.lambdaQuery().eq(User::getAccount, account).one();
        if (user == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户不存在");
        }

        SubmitHistoryVO submitHistoryVO = new SubmitHistoryVO();

        // 获取一年前的日期
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.YEAR, -1);
        Date oneYearAgo = calendar.getTime();

        // 查询该用户一年内的所有提交记录
        List<Answer> answers = answerService.lambdaQuery()
                .eq(Answer::getUserId, user.getId())
                .ge(Answer::getSubmitTime, oneYearAgo)
                .list();

        // 按日期分组统计提交次数
        Map<String, Long> submitCountMap = answers.stream()
                .collect(Collectors.groupingBy(
                        answer -> {
                            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                            return sdf.format(answer.getSubmitTime());
                        },
                        Collectors.counting()
                ));

        // 转换为VO列表
        List<List<String>> data = submitCountMap.entrySet().stream()
                .map(entry -> {
                    ArrayList<String> list = new ArrayList<>();
                    list.add(entry.getKey());
                    list.add(entry.getValue().toString());
                    return list;
                })
                .collect(Collectors.toList());
        submitHistoryVO.setData(data);

        // 计算总提交次数
        int totalSubmissions = answers.size();
        submitHistoryVO.setTotalSubmit(totalSubmissions);

        // 计算累计提交天数
        int totalSubmitDays = submitCountMap.size();
        submitHistoryVO.setTotalSubmitDay(totalSubmitDays);

        // 计算最大连续提交天数
        int maxConsecutiveDays = calculateMaxConsecutiveDays(submitCountMap);
        submitHistoryVO.setContinuousSubmit(maxConsecutiveDays);

        return submitHistoryVO;
    }

    @Override
    public void judgeChoice(JudgeDTO judgeDTO, String submissionId) {
        Answer answer = new Answer();
        answer.setQuestionId(judgeDTO.getQuestionId());
        answer.setUserId(getUserId(submissionId));
        answer.setSubmissionId(submissionId);
        answer.setJudgeTime(new Date());
        answer.setUserInput(GSON.toJson(judgeDTO.getMultipleChoice()));
        LambdaQueryWrapper<Answer> queryWrapper = createSubmissionIdQueryWrapper(submissionId);

        // 判断
        List<ChoiceQuestion> choiceQuestionList = choiceQuestionService.lambdaQuery()
                .eq(ChoiceQuestion::getIsCorrect, 1)
                .eq(ChoiceQuestion::getQuestionId, judgeDTO.getQuestionId())
                .list();
        if (choiceQuestionList == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "题目参数不正确");
        }
        if (choiceQuestionList.size() == 1) {
            // 单选题
            Integer correct = Integer.valueOf(String.valueOf(choiceQuestionList.get(0).getId()));
            if (correct.equals(judgeDTO.getMultipleChoice().get(0))) {
                answer.setStatus(JudgeResultConstants.ACCEPTED);
                answer.setScore(choiceQuestionList.get(0).getScore());
            } else {
                answer.setStatus(JudgeResultConstants.WRONG_ANSWER);
                answer.setScore(0);
            }
        } else {
            // 多选题
            if (judgeDTO.getMultipleChoice().size() == choiceQuestionList.size()) {
                List<Integer> userInputList = judgeDTO.getMultipleChoice().stream()
                        .map(choice -> Integer.valueOf(String.valueOf(choice))).collect(Collectors.toList());
                List<Integer> correctIdList = choiceQuestionList.stream()
                        .map(choiceQuestion -> Integer.valueOf(String.valueOf(choiceQuestion.getId())))
                        .collect(Collectors.toList());
                if (new HashSet<>(userInputList).containsAll(correctIdList)) {
                    answer.setStatus(JudgeResultConstants.ACCEPTED);
                    answer.setScore(choiceQuestionList.get(0).getScore());
                } else {
                    answer.setStatus(JudgeResultConstants.WRONG_ANSWER);
                    answer.setScore(0);
                }
            } else {
                answer.setStatus(JudgeResultConstants.WRONG_ANSWER);
                answer.setScore(0);
            }
        }


        answerService.update(answer, queryWrapper);
    }

    @Override
    public void judgeJudgement(JudgeDTO judgeDTO, String submissionId) {
        Answer answer = new Answer();
        answer.setQuestionId(judgeDTO.getQuestionId());
        answer.setUserId(getUserId(submissionId));
        answer.setSubmissionId(submissionId);
        answer.setJudgeTime(new Date());
        answer.setUserInput(String.valueOf(judgeDTO.getJudgement()));
        LambdaQueryWrapper<Answer> queryWrapper = createSubmissionIdQueryWrapper(submissionId);

        //获取正确答案
        JudgmentQuestion judgmentQuestion = judgmentQuestionService.lambdaQuery()
                .eq(JudgmentQuestion::getQuestionId, judgeDTO.getQuestionId())
                .one();
        if (judgmentQuestion == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "题目参数不正确");
        }
        if (Objects.equals(judgeDTO.getJudgement(), judgmentQuestion.getIsCorrect())) {
            answer.setStatus(JudgeResultConstants.ACCEPTED);
            answer.setScore(judgmentQuestion.getScore());
        } else {
            answer.setStatus(JudgeResultConstants.WRONG_ANSWER);
            answer.setScore(0);
        }

        answerService.update(answer, queryWrapper);
    }

    @Override
    public void judgeFillBlank(JudgeDTO judgeDTO, String submissionId) {
        Answer answer = new Answer();
        answer.setQuestionId(judgeDTO.getQuestionId());
        answer.setUserId(getUserId(submissionId));
        answer.setSubmissionId(submissionId);
        answer.setJudgeTime(new Date());
        String userInputStr = GSON.toJson(judgeDTO.getFillBlanks());
        answer.setUserInput(userInputStr);
        LambdaQueryWrapper<Answer> queryWrapper = createSubmissionIdQueryWrapper(submissionId);

        //获取正确答案
        FillBlanksQuestion fillBlanksQuestion = fillBlanksQuestionService.lambdaQuery()
                .eq(FillBlanksQuestion::getQuestionId, judgeDTO.getQuestionId())
                .one();
        String correctAnswer = fillBlanksQuestion.getAnswer();
        if (StringUtils.isAnyBlank(userInputStr, correctAnswer)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "题目参数不正确");
        }
        if (userInputStr.equals(correctAnswer)) {
            answer.setStatus(JudgeResultConstants.ACCEPTED);
            answer.setScore(fillBlanksQuestion.getScore());
        } else {
            answer.setStatus(JudgeResultConstants.WRONG_ANSWER);
            answer.setScore(0);
        }

        answerService.update(answer, queryWrapper);
    }

    @Override
    public void judgeComprehensive(JudgeDTO judgeDTO, String submissionId) {
        Answer answer = new Answer();
        answer.setQuestionId(judgeDTO.getQuestionId());
        answer.setUserId(getUserId(submissionId));
        answer.setSubmissionId(submissionId);
        answer.setJudgeTime(new Date());
        answer.setUserInput(judgeDTO.getComprehensive());
        LambdaQueryWrapper<Answer> queryWrapper = createSubmissionIdQueryWrapper(submissionId);

        ComprehensiveQuestion comprehensiveQuestion = comprehensiveQuestionService.lambdaQuery()
                .eq(ComprehensiveQuestion::getQuestionId, judgeDTO.getQuestionId())
                .one();
        Question question = questionService.getById(judgeDTO.getQuestionId());

        JudgeComprehensiveBO judgeComprehensiveBO = new JudgeComprehensiveBO();
        judgeComprehensiveBO.setContent(question.getContent());
        judgeComprehensiveBO.setComprehensive(judgeDTO.getComprehensive());
        judgeComprehensiveBO.setReferenceAnswer(comprehensiveQuestion.getReferenceAnswer());
        judgeComprehensiveBO.setMaxScore(comprehensiveQuestion.getScore());

        String jsonStr = GSON.toJson(judgeComprehensiveBO);
        String message = String.format(
                JudgeConstants.COMPREHENSIVE_QUESTION_JUDGE_PROMPT,
                jsonStr
        );
        AIResult result = AIUtils.getInstance().sendMessage(message, false, false);
        String handledResult = handleResult(result.getContent());
        try {
            JsonObject jsonObject = GSON.fromJson(handledResult, JsonObject.class);
            if (jsonObject.has("score") && jsonObject.has("comment")) {
                answer.setScore(jsonObject.get("score").getAsInt());
                answer.setSuggestion(jsonObject.get("comment").getAsString());
            }
        } catch (Exception e) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR);
        }
        if (answer.getScore() >= comprehensiveQuestion.getScore()) {
            answer.setStatus(JudgeResultConstants.ACCEPTED);
        }
        if (answer.getScore() < comprehensiveQuestion.getScore()) {
            answer.setStatus(JudgeResultConstants.PARTIAL_ACCEPTED);
        }
        if (answer.getScore() <= 0) {
            answer.setStatus(JudgeResultConstants.WRONG_ANSWER);
        }
        answerService.update(answer, queryWrapper);
    }

    private String handleResult(String content) {
        // 移除可能存在的JSON代码块标记
        return content.replaceAll("^```json\\s*|\\s*```$", "").trim();
    }

    /**
     * 计算最大连续提交天数
     *
     * @param submitCountMap 提交记录映射
     * @return 最大连续提交天数
     */
    private int calculateMaxConsecutiveDays(Map<String, Long> submitCountMap) {
        if (submitCountMap.isEmpty()) {
            return 0;
        }

        // 将所有提交日期转换为LocalDate并排序
        List<LocalDate> submitDates = submitCountMap.keySet().stream()
                .map(LocalDate::parse)
                .sorted()
                .collect(Collectors.toList());

        int maxStreak = 1;
        int currentStreak = 1;

        for (int i = 1; i < submitDates.size(); i++) {
            LocalDate previousDate = submitDates.get(i - 1);
            LocalDate currentDate = submitDates.get(i);

            if (previousDate.plusDays(1).equals(currentDate)) {
                currentStreak++;
                maxStreak = Math.max(maxStreak, currentStreak);
            } else {
                currentStreak = 1;
            }
        }

        return maxStreak;
    }

    /**
     * 处理空代码情况
     *
     * @param answer       答案
     * @param submissionId 提交ID
     */
    private void handleEmptyCode(Answer answer, String submissionId) {
        LambdaQueryWrapper<Answer> queryWrapper = createSubmissionIdQueryWrapper(submissionId);

        answer.setStatus(JudgeResultConstants.COMPILE_ERROR);
        answer.setTime(0);
        answer.setMemory(0);
        answer.setScore(0);
        answer.setCompilerOutput("代码不能为空");
        answerService.update(answer, queryWrapper);
    }

    /**
     * 创建基于提交ID的查询包装器
     *
     * @param submissionId 提交ID
     * @return 查询包装器
     */
    private LambdaQueryWrapper<Answer> createSubmissionIdQueryWrapper(String submissionId) {
        LambdaQueryWrapper<Answer> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Answer::getSubmissionId, submissionId);
        return queryWrapper;
    }

    /**
     * 根据题目ID获取测试用例列表
     *
     * @param questionId 题目ID
     * @return 测试用例列表
     */
    private List<TestCase> getTestCaseInfoList(Long questionId) {
        return testCaseService.lambdaQuery()
                .eq(TestCase::getQuestionId, questionId)
                .list();
    }

    /**
     * 根据提交ID获取答案
     *
     * @param submissionId 提交ID
     * @return 答案
     */
    private Answer getAnswerBySubmissionId(String submissionId) {
        Answer answer = answerService.lambdaQuery()
                .eq(Answer::getSubmissionId, submissionId)
                .one();

        if (answer == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "提交记录不存在");
        }

        return answer;
    }

    /**
     * 获取当前用户ID
     *
     * @return 用户ID或null
     */
    private Long getCurrentUserId() {
        Object object = StpUtil.getLoginIdDefaultNull();
        if (object == null) {
            return null;
        }
        return Long.parseLong(String.valueOf(object));
    }

    /**
     * 根据用户ID和题目ID获取最后一次提交记录
     *
     * @param userId     用户ID
     * @param questionId 题目ID
     * @return 最后一次提交记录
     */
    private Answer getLastAnswerByUserAndQuestion(Long userId, Long questionId) {
        Answer answer = answerService.lambdaQuery()
                .eq(Answer::getUserId, userId)
                .eq(Answer::getQuestionId, questionId)
                .orderByDesc(Answer::getSubmitTime)
                .last("limit 1")
                .one();

        if (answer == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "提交记录不存在");
        }

        return answer;
    }

    /**
     * 构建执行代码结果视图对象
     *
     * @param answer   答案记录
     * @param username 用户名
     * @return 执行代码结果视图对象
     */
    private ExecuteCodeVO buildExecuteCodeVO(Answer answer, String username) {
        ExecuteCodeVO executeCodeVO = new ExecuteCodeVO();

        // 获取题目信息
        Question question = questionService.getById(answer.getQuestionId());
        executeCodeVO.setQuestionType(question.getType());
        executeCodeVO.setQuestionName(question.getTitle());
        executeCodeVO.setUsername(username);
        executeCodeVO.setSubmitTime(answer.getCreateTime());
        executeCodeVO.setJudgeTime(answer.getUpdateTime());
        executeCodeVO.setSubmitTime(answer.getSubmitTime());
        executeCodeVO.setJudgeTime(answer.getJudgeTime());
        executeCodeVO.setStatus(answer.getStatus());
        executeCodeVO.setUserInput(answer.getUserInput());
        if (question.getType().equals(QuestionTypeEnum.MULTIPLE_CHOICE.getCode())) {
            List<String> idList = GSON.fromJson(answer.getUserInput(), STRING_LIST_TYPE);
            List<String> optionList = idList.stream().map(id -> {
                ChoiceQuestion choiceQuestion = choiceQuestionService.getById(id);
                return choiceQuestion.getOption();
            }).collect(Collectors.toList());
            executeCodeVO.setUserInput(GSON.toJson(optionList));
        }
        if (question.getType().equals(QuestionTypeEnum.PROGRAMMING.getCode())) {
            executeCodeVO.setCompiler(judgeManager.getCompilerName(answer.getLanguage()));
            executeCodeVO.setCode(answer.getUserInput());
            executeCodeVO.setCompilerOutput(answer.getCompilerOutput());
            executeCodeVO.setErrorMessage(answer.getErrorMessage());
            ProgrammingQuestion programmingQuestion = programmingQuestionService.lambdaQuery()
                    .eq(ProgrammingQuestion::getQuestionId, answer.getQuestionId())
                    .one();

            executeCodeVO.setTime(answer.getTime() + " / " + programmingQuestion.getTimeLimit() + " ms");
            executeCodeVO.setMemory(answer.getMemory() + " / " + programmingQuestion.getMemoryLimit() + " KB");

            List<TestCase> testCaseList = getTestCaseInfoList(answer.getQuestionId());

            executeCodeVO.setScore(answer.getScore() + " / " + judgeManager.calculateMaxScore(testCaseList));

            // 构建测试用例结果
            executeCodeVO.setTestCaseList(buildTestCaseVOList(answer.getSubmissionId()));
        }
        if (question.getType().equals(QuestionTypeEnum.MULTIPLE_CHOICE.getCode())) {
            List<ChoiceQuestion> choiceQuestionList = choiceQuestionService.lambdaQuery()
                    .eq(ChoiceQuestion::getQuestionId, question.getId())
                    .list();
            executeCodeVO.setScore(answer.getScore() + "/" + choiceQuestionList.get(0).getScore());
            List<ChoiceOptionVO> choiceOptionVOList = choiceQuestionList.stream().map(choiceQuestion -> {
                ChoiceOptionVO choiceOptionVO = new ChoiceOptionVO();
                choiceOptionVO.setOption(choiceQuestion.getOption());
                choiceOptionVO.setIsCorrect(choiceQuestion.getIsCorrect());
                choiceOptionVO.setAnalysis(choiceQuestion.getAnalysis());
                return choiceOptionVO;
            }).collect(Collectors.toList());
            executeCodeVO.setChoiceOptionList(choiceOptionVOList);
        }
        if (question.getType().equals(QuestionTypeEnum.JUDGEMENT.getCode())) {
            JudgmentQuestion judgmentQuestion = judgmentQuestionService.lambdaQuery()
                    .eq(JudgmentQuestion::getQuestionId, question.getId())
                    .one();
            executeCodeVO.setAnalysis(judgmentQuestion.getAnalysis());
            executeCodeVO.setScore(answer.getScore() + "/" + judgmentQuestion.getScore());
            executeCodeVO.setJudgement(judgmentQuestion.getIsCorrect());
        }
        if (question.getType().equals(QuestionTypeEnum.FILL_BLANK.getCode())) {
            FillBlanksQuestion fillBlanksQuestion = fillBlanksQuestionService.lambdaQuery()
                    .eq(FillBlanksQuestion::getQuestionId, question.getId())
                    .one();
            executeCodeVO.setScore(answer.getScore() + "/" + fillBlanksQuestion.getScore());
            executeCodeVO.setAnalysis(fillBlanksQuestion.getAnalysis());
            executeCodeVO.setFillBlanks(GSON.fromJson(fillBlanksQuestion.getAnswer(), STRING_LIST_TYPE));
        }
        if (question.getType().equals(QuestionTypeEnum.COMPREHENSIVE.getCode())) {
            ComprehensiveQuestion comprehensiveQuestion = comprehensiveQuestionService.lambdaQuery()
                    .eq(ComprehensiveQuestion::getQuestionId, question.getId())
                    .one();
            executeCodeVO.setScore(answer.getScore() + "/" + comprehensiveQuestion.getScore());
            executeCodeVO.setComprehensive(comprehensiveQuestion.getReferenceAnswer());
            executeCodeVO.setSuggestion(answer.getSuggestion());
        }
        return executeCodeVO;
    }

    /**
     * 得到选择题总分
     *
     * @param questionId 题目ID
     * @return {@link Integer }
     */
    private Integer getChoiceQuestionMaxScore(Long questionId) {
        return choiceQuestionService.lambdaQuery()
                .eq(ChoiceQuestion::getQuestionId, questionId)
                .list()
                .get(0)
                .getScore();
    }

    /**
     * 构建测试用例结果列表
     *
     * @param submissionId 提交ID
     * @return 测试用例结果列表
     */
    private List<TestCaseVO> buildTestCaseVOList(String submissionId) {
        List<JudgeCode> judgeCodeList = this.lambdaQuery()
                .eq(JudgeCode::getSubmissionId, submissionId)
                .list();

        return judgeCodeList.stream().map(judgeCodeInfo -> {
            TestCaseVO testCaseVO = new TestCaseVO();
            testCaseVO.setTime(judgeCodeInfo.getTime());
            testCaseVO.setMemory(judgeCodeInfo.getMemory());
            testCaseVO.setScore(judgeCodeInfo.getScore());
            testCaseVO.setHint(judgeCodeInfo.getHint());
            // 根据分数判断状态
            Long testCaseId = judgeCodeInfo.getTestCaseId();
            TestCase testCase = testCaseService.getById(testCaseId);
            if (Objects.equals(testCase.getScore(), judgeCodeInfo.getScore())) {
                testCaseVO.setStatus(JudgeResultConstants.ACCEPTED);
            } else if (judgeCodeInfo.getScore() < testCase.getScore()) {
                testCaseVO.setStatus(JudgeResultConstants.PARTIAL_ACCEPTED);
            } else {
                testCaseVO.setStatus(JudgeResultConstants.WRONG_ANSWER);
            }
            return testCaseVO;
        }).collect(Collectors.toList());
    }

    /**
     * 初始化答案对象
     *
     * @param judgeDTO     执行代码dto
     * @param submissionId 提交id
     * @return {@link Answer }
     */
    private Answer initializeAnswer(JudgeDTO judgeDTO, String submissionId) {
        Answer answer = new Answer();
        answer.setQuestionId(judgeDTO.getQuestionId());
        answer.setUserId(getUserId(submissionId));
        answer.setSubmissionId(submissionId);
        answer.setLanguage(judgeDTO.getLanguage());
        answer.setUserInput(judgeDTO.getCode());
        return answer;
    }

    /**
     * 根据ID获取题目
     *
     * @param questionId 题目身份证件
     * @return {@link Question }
     */
    private Question getQuestionById(Long questionId) {
        Question question = questionService.getById(questionId);
        if (question == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "题目不存在");
        }
        return question;
    }

    /**
     * 获取登录用户名
     *
     * @return {@link String }
     */
    private String getUsername(String submissionId) {
        WebSocketSession session = JudgeHandler.getSession(submissionId);
        Long userId = (Long) session.getAttributes().get("userId");
        if (userId == null) {
            log.error("Attempted to get user info without login");
            throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR);
        }
        User user = userService.getById(Long.parseLong(userId.toString()));
        return user.getUsername();
    }

    private Long getUserId(String submissionId) {
        WebSocketSession session = JudgeHandler.getSession(submissionId);
        return (Long) session.getAttributes().get("userId");
    }

    /**
     * 处理测试用例
     */
    private List<TestCaseVO> handleTestCases(List<ExecuteMessage> executeMessageList,
                                             Map<Long, String> answerMap,
                                             java.util.concurrent.atomic.AtomicInteger totalScore,
                                             String submissionId,
                                             Long userId) {
        return executeMessageList.stream().map(executeMessage -> {
            Long testCaseId = executeMessage.getTestCaseId();
            TestCaseVO testCaseVO = new TestCaseVO();
            JudgeCode judgeCode = new JudgeCode();
            judgeCode.setSubmissionId(submissionId);
            judgeCode.setUserId(userId);
            judgeCode.setTestCaseId(testCaseId);
            judgeCode.setHint(executeMessage.getHint());
            judgeCode.setTime(executeMessage.getTime());
            judgeCode.setMemory(executeMessage.getMemory());
            judgeCode.setScore(executeMessage.getScore());

            testCaseVO.setHint(executeMessage.getHint());
            testCaseVO.setMemory(executeMessage.getMemory());
            testCaseVO.setTime(executeMessage.getTime());

            if (!executeMessage.getExitValue().equals(0)) {
                testCaseVO.setStatus(JudgeResultConstants.NON_ZERO_RETURN);
                testCaseVO.setScore(0);

                judgeCode.setScore(0);
                this.save(judgeCode);
                return testCaseVO;
            }

            String answer = answerMap.get(testCaseId);
            if (!answer.equals(executeMessage.getMessage())) {
                testCaseVO.setStatus(JudgeResultConstants.WRONG_ANSWER);
                testCaseVO.setScore(0);

                judgeCode.setScore(0);
                this.save(judgeCode);
                return testCaseVO;
            }

            totalScore.addAndGet(executeMessage.getScore());
            testCaseVO.setStatus(JudgeResultConstants.ACCEPTED);
            testCaseVO.setScore(executeMessage.getScore());

            judgeCode.setScore(executeMessage.getScore());
            this.save(judgeCode);
            return testCaseVO;
        }).collect(Collectors.toList());
    }

    /**
     * 获取最大运行时间
     */
    private long getMaxTime(List<TestCaseVO> testCaseVOList) {
        return testCaseVOList.stream()
                .mapToLong(TestCaseVO::getTime)
                .max()
                .orElse(0L);
    }

    /**
     * 获取最大内存使用
     */
    private long getMaxMemory(List<TestCaseVO> testCaseVOList) {
        return testCaseVOList.stream()
                .mapToLong(TestCaseVO::getMemory)
                .max()
                .orElse(0L);
    }
}